/*
 * MainFrameBase.java
 *
 * Created on January 28, 2007, 9:38 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package com.bff.mpd.musicjukebox.ui;

import com.bff.bjj.ui.BJJFrame;
import com.bff.bjj.ui.LAFChangeListener;
import com.bff.mpd.musicjukebox.lib.JukeboxProperties;
import com.bff.bjj.ui.component.BJJPanel;
import com.bff.mpd.utils.Utils;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import java.awt.AWTException;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.awt.event.WindowListener;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import org.bff.javampd.MPDDatabase;
import org.bff.javampd.MPDPlayer;
import org.bff.javampd.MPDPlaylist;
import org.bff.javampd.events.ConnectionChangeListener;
import org.bff.javampd.events.PlayerBasicChangeListener;
import org.bff.javampd.events.PlayerChangeListener;
import org.bff.javampd.events.PlaylistBasicChangeListener;
import org.bff.javampd.events.PlaylistChangeListener;
import org.bff.javampd.events.TrackPositionChangeEvent;
import org.bff.javampd.events.TrackPositionChangeListener;
import org.bff.javampd.exception.MPDConnectionException;
import org.bff.javampd.exception.MPDPlayerException;

/**
 *
 * @author Bill
 */
public abstract class MainFrameBase
        extends BJJFrame
        implements TrackPositionChangeListener,
        PlaylistBasicChangeListener,
        PlaylistChangeListener,
        PlayerBasicChangeListener,
        PlayerChangeListener,
        ConnectionChangeListener,
        WindowFocusListener,
        WindowListener,
        LAFChangeListener {

    private MPDPlaylist playlist;
    private MPDPlayer player;
    private MPDDatabase database;
    // ui stuff
    protected BJJPanel guitarTabPanel;
    protected BJJPanel statTabPanel;
    protected com.bff.mpd.musicjukebox.ui.GuitarPanel guitarPanel;
    protected com.bff.mpd.musicjukebox.ui.StatMPDPanel mpdPanel;
    public com.bff.mpd.musicjukebox.ui.PlayerPanelThin playerPanel;
    protected javax.swing.JTabbedPane mainTabbedPane;
    protected TrayIcon trayIcon;
    protected static JPanel minimizePanel;
    private static JFrame frame;
    private static int oldX;
    private static int oldY;
    private static Dimension oldSize;
    private boolean loaded;
    private JukeboxProperties jp;

    /** Creates a new instance of MainFrameBase */
    public MainFrameBase(SplashScreen sp) {
        try {
            jp = JukeboxProperties.getInstance();
            setPlaylist(jp.getPlaylist());
            setPlayer(jp.getPlayer());
            setDatabase(jp.getDatabase());

            makeActions();
            mainTabbedPane = new JTabbedPane();
            createGUI();

            jp.getMPDMonitor().addTrackPositionChangeListener(this);
            jp.getMPDMonitor().addPlayerChangeListener(this);
            jp.getMPDMonitor().addPlaylistChangeListener(this);
            jp.getMPDMonitor().addConnectionChangeListener(this);

            getPlaylist().addPlaylistChangeListener(this);

            // guitar panel
            if (jp.showGuitarPanel()) {
                addGuitarPanel();
            }

            statTabPanel = new BJJPanel();
            statTabPanel.setLayout(new java.awt.FlowLayout());

            // mpd panel
            mpdPanel = new StatMPDPanel();
            statTabPanel.add(mpdPanel);
            mainTabbedPane.insertTab(Utils.getMessage("TAB_STATS"), null, statTabPanel, null, 4);

            addWindowListener(this);
            frame = this;
            setMinimizePanel();
            if (jp.isTrayAlways()) {
                loadIntoTray();
            }
            setLoaded(true);
        } catch (Exception e) {
            e.printStackTrace();
            new ErrorDialog(this, "An Error Has Occurred", e);
        } finally {
            sp.setStopped(true);
        }
    }

    @Override
    public void trackPositionChanged(TrackPositionChangeEvent event) {
        if (playerPanel != null) {
            playerPanel.setElapsedTrackTime(event.getElapsedTime());
        }

        if (guitarPanel != null) {
            guitarPanel.setElapsedTrackTime(event.getElapsedTime());
        }
    }

    @Override
    public void dispose() {
        checkPlayer();
        super.dispose();
    }

    private void checkPlayer() {
        if (jp.isStopOnExit()) {
            try {
                jp.getPlayer().stop();
            } catch (MPDConnectionException ex) {
                Logger.getLogger(MainFrameBase.class.getName()).log(Level.SEVERE, null, ex);
            } catch (MPDPlayerException ex) {
                Logger.getLogger(MainFrameBase.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public abstract void makeActions();

    public abstract void createGUI();

    public abstract void addGuitarPanel();

    @Override
    public void windowGainedFocus(WindowEvent e) {
    }

    @Override
    public void windowLostFocus(WindowEvent e) {
    }

    @Override
    public void windowClosing(java.awt.event.WindowEvent evt) {
        if (jp.isStopOnExit()) {
            try {
                getPlayer().stop();
            } catch (MPDConnectionException ex) {
                Logger.getLogger(MainFrameBase.class.getName()).log(Level.SEVERE, null, ex);
            } catch (MPDPlayerException ex) {
                Logger.getLogger(MainFrameBase.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    @Override
    public void windowOpened(WindowEvent e) {
    }

    @Override
    public void windowClosed(WindowEvent e) {
        checkPlayer();
        System.exit(0);
    }

    @Override
    public void windowIconified(WindowEvent e) {
        if (jp.isTrayMin()) {
            minimizeToTray();
        }
    }

    @Override
    public void windowDeiconified(WindowEvent e) {
    }

    @Override
    public void windowActivated(WindowEvent e) {
    }

    @Override
    public void windowDeactivated(WindowEvent e) {
    }

    protected void minimizeToTray() {
        loadIntoTray();
    }

    public abstract void setMinimizePanel();

    public static void maximizePanel() {
        minimizePanel.setVisible(true);
        frame.setLocation(oldX, oldY);
        frame.setSize(oldSize);
    }

    public static void minimizePanel() {
        oldX = frame.getX();
        oldY = frame.getY();
        oldSize = frame.getSize();

        minimizePanel.setVisible(false);
        frame.pack();
    }

    @Override
    public boolean isMiniPlayer() {
        return !minimizePanel.isVisible();
    }

    /** Returns an ImageIcon, or null if the path was invalid. */
    protected ImageIcon createImageIcon(String path, String description) {
        java.net.URL imgURL = getClass().getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL, description);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }

    /**
     * @return the playlist
     */
    public MPDPlaylist getPlaylist() {
        return playlist;
    }

    /**
     * @param playlist the playlist to set
     */
    public void setPlaylist(MPDPlaylist playlist) {
        this.playlist = playlist;
    }

    /**
     * @return the player
     */
    public MPDPlayer getPlayer() {
        return player;
    }

    /**
     * @param player the player to set
     */
    public void setPlayer(MPDPlayer player) {
        this.player = player;
    }

    /**
     * @return the database
     */
    public MPDDatabase getDatabase() {
        return database;
    }

    /**
     * @param database the database to set
     */
    public void setDatabase(MPDDatabase database) {
        this.database = database;
    }

    /**
     * @return the loaded
     */
    public boolean isLoaded() {
        return loaded;
    }

    /**
     * @param loaded the loaded to set
     */
    public void setLoaded(boolean loaded) {
        this.loaded = loaded;
    }

    @Override
    public void positionWindow() {
        // set frame nicely in screen
        Toolkit tk = Toolkit.getDefaultToolkit();
        Dimension d = tk.getScreenSize();
        if (d.height > 768 && d.width > 1024) {
            Rectangle rect = new Rectangle((int) (d.width / 1.2),
                    (int) (d.height / 1.2));
            setBounds(rect);

            int heightScreen = d.height / 2;
            int widthScreen = d.width / 2;
            setLocation(widthScreen - (int) (getWidth() / 2), heightScreen - (int) (getHeight() / 2));
        } else {
            setExtendedState(JFrame.MAXIMIZED_BOTH);
        }
    }

    private void loadIntoTray() {
        if (SystemTray.isSupported()) {

            final SystemTray tray = SystemTray.getSystemTray();
            final Image image1 = createImageIcon("/resources/mpd/bjjicontray.jpg", "icon image").getImage();

            MouseListener mouseListener = new MouseListener() {

                @Override
                public void mouseClicked(MouseEvent e) {
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                }

                @Override
                public void mouseExited(MouseEvent e) {
                }

                @Override
                public void mousePressed(MouseEvent e) {
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                }
            };

            ActionListener exitListener = new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    System.out.println("Exiting...");
                    System.exit(0);
                }
            };

            ActionListener stopListener = new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    try {
                        getPlayer().stop();
                    } catch (MPDConnectionException ex) {
                        Logger.getLogger(MainFrameBase.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (MPDPlayerException ex) {
                        Logger.getLogger(MainFrameBase.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            };

            ActionListener pauseListener = new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    try {
                        getPlayer().pause();
                    } catch (MPDConnectionException ex) {
                        Logger.getLogger(MainFrameBase.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (MPDPlayerException ex) {
                        Logger.getLogger(MainFrameBase.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            };

            ActionListener playListener = new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    try {
                        getPlayer().play();
                    } catch (MPDConnectionException ex) {
                        Logger.getLogger(MainFrameBase.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (MPDPlayerException ex) {
                        Logger.getLogger(MainFrameBase.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            };

            ActionListener restoreListener = new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    setExtendedState(NORMAL);
                    setVisible(true);
                    requestFocus();
                    toFront();
                    tray.remove(trayIcon);
                }
            };

            PopupMenu popup = new PopupMenu();
            MenuItem restoreItem = new MenuItem(Utils.getMessage("TRAY_RESTORE"));
            restoreItem.addActionListener(restoreListener);
            MenuItem playItem = new MenuItem(Utils.getMessage("TRAY_PLAY"));
            playItem.addActionListener(playListener);
            MenuItem pauseItem = new MenuItem(Utils.getMessage("TRAY_PAUSE"));
            pauseItem.addActionListener(pauseListener);
            MenuItem stopItem = new MenuItem(Utils.getMessage("TRAY_STOP"));
            stopItem.addActionListener(stopListener);
            MenuItem exitItem = new MenuItem(Utils.getMessage("TRAY_EXIT"));
            exitItem.addActionListener(exitListener);

            popup.add(restoreItem);
            popup.add(playItem);
            popup.add(pauseItem);
            popup.add(stopItem);
            popup.add(exitItem);

            trayIcon = new TrayIcon(image1, Utils.getMessage("TRAY_TEXT"), popup);

            ActionListener actionListener = new ActionListener() {

                public void actionPerformed(ActionEvent e) {
                    trayIcon.displayMessage(Utils.getMessage("TRAY_CAPTION"),
                            Utils.getMessage("TRAY_TEXT"),
                            TrayIcon.MessageType.INFO);
                }
            };

            trayIcon.setImageAutoSize(true);
            trayIcon.addActionListener(restoreListener);
            trayIcon.addMouseListener(mouseListener);

            try {
                tray.add(trayIcon);
            } catch (AWTException e) {
                System.err.println("TrayIcon could not be added.");
            }

            if (!jp.isTrayAlways()) {
                setVisible(false);
            }

        } else {
            //System Tray is not supported
        }
    }
}
